package shop

import (
	"gdshop-back-end-go/admin-api/app/controllers"
	toolsDb "gdshop-back-end-go/common/db"
	"gdshop-back-end-go/common/entity"
	"gdshop-back-end-go/common/request/BaseReq"
	"gdshop-back-end-go/common/request/OrderReq"
	"gdshop-back-end-go/common/tools"
	"gdshop-back-end-go/common/wxpayHelper"
	"gdshop-back-end-go/service-order/OrderService"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/net/ghttp"
	"github.com/gogf/gf/util/gconv"
	"github.com/shenghui0779/gochat/mch"
	"github.com/shenghui0779/gochat/wx"
	"strings"
)

// PayNotifyController 支付回调
type PayNotifyController struct {
	*ShopBaseController
}

func NewPayNotifyController(inputReq *BaseReq.I) *PayNotifyController {
	return &PayNotifyController{
		&ShopBaseController{&controllers.BaseController{Req: inputReq}},
	}
}
func addErrorLog(catName, errMsg string) {
	g.Log().Async().Cat("PayNotify_" + catName).Error(errMsg)
}
func (c *PayNotifyController) WechatpayOa(r *ghttp.Request) {
	wxpay := wxpayHelper.GetWxpay(false)
	bodyData := r.GetMap()
	data := wx.WXML{}
	for k, item := range bodyData {
		data[k] = gconv.String(item)
	}
	err := wxpay.VerifyWXMLResult(data)
	if err != nil {
		addErrorLog("WechatpayOa", "签名验证失败 body "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("签名验证失败"))
		return
	}

	/*
		返回示例
		<xml>
		  <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
		  <attach><![CDATA[支付测试]]></attach>
		  <bank_type><![CDATA[CFT]]></bank_type>
		  <fee_type><![CDATA[CNY]]></fee_type>
		  <is_subscribe><![CDATA[Y]]></is_subscribe>
		  <mch_id><![CDATA[10000100]]></mch_id>
		  <nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str>
		  <openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid>
		  <out_trade_no><![CDATA[1409811653]]></out_trade_no>
		  <result_code><![CDATA[SUCCESS]]></result_code>
		  <return_code><![CDATA[SUCCESS]]></return_code>
		  <sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign>
		  <time_end><![CDATA[20140903131540]]></time_end>
		  <total_fee>1</total_fee>
		  <coupon_fee><![CDATA[10]]></coupon_fee>
		  <coupon_count><![CDATA[1]]></coupon_count>
		  <coupon_type><![CDATA[CASH]]></coupon_type>
		  <coupon_id><![CDATA[10000]]></coupon_id>
		  <trade_type><![CDATA[JSAPI]]></trade_type>
		  <transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>
		</xml>
	*/
	if !(data["result_code"] == "SUCCESS" && data["return_code"] == "SUCCESS") {
		addErrorLog("WechatpayOa", "状态码不对 "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("状态码不对"))
		return
	}

	// 签名通过
	// 查询 pay_log 是否有记录
	ctx := r.GetCtx()
	var plModel *entity.PayLog
	err = toolsDb.GetUnSafaTable(ctx, "pay_log").Where("order_id", data["out_trade_no"]).Struct(&plModel)
	if err != nil {
		addErrorLog("WechatpayOa", "pay_log 找不到数据 "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("记录不存在"))
		return
	}
	if plModel == nil {
		addErrorLog("WechatpayOa", "pay_log 找不到数据 "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("记录不存在"))
		return
	}
	tmps := strings.Split(plModel.OrderId, "F")
	if len(tmps) != 2 {
		addErrorLog("WechatpayOa", "pay_log order_id 解析失败 "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("记录不存在"))
		return
	}

	// 通过openid 反查 memberid 如果查不到则为0
	memberId := 0
	value, err := toolsDb.GetUnSafaTable(ctx, "member_wechat").Where("openid", data["openid"]).
		Fields("member_id").Value()
	if err == nil {
		memberId = value.Int()
	}

	jieguo := OrderService.ChangeStatus(ctx, &OrderReq.ChangeStatus{
		Type:     "member_pay",
		OrderId:  gconv.Int(tmps[0]),
		Payment:  "wechatpay",
		MemberId: memberId,
		PayLogId: plModel.Id,
	})

	if jieguo.Code == 0 {
		// 更新 pay_log
		_, err := toolsDb.GetUnSafaTable(ctx, "pay_log").Where("id", plModel.Id).Update(g.Map{
			"update_time": tools.MakeTimestamp(),
			"status":      1,
		})
		if err != nil {
			addErrorLog("WechatpayOa", "更新 pay_log 失败 id:"+gconv.String(plModel.Id)+
				" error:"+err.Error())
			return
		}
		r.Response.WriteXmlExit(mch.ReplyOK())
		return
	} else {
		addErrorLog("WechatpayOa", "ChangeStatus 失败 "+r.GetBodyString()+" error:"+jieguo.Message)
		r.Response.WriteXmlExit(mch.ReplyFail("改变订单失败"))
		return
	}
}

func (c *PayNotifyController) WechatpayRefundOa(r *ghttp.Request) {
	wxpay := wxpayHelper.GetWxpay(false)
	bodyData := r.GetMap()
	if bodyData["return_code"] != "SUCCESS" {
		r.Response.WriteXmlExit(mch.ReplyFail("状态码不对"))
		return
	}
	tmpData := wx.WXML{}
	for k, item := range bodyData {
		tmpData[k] = gconv.String(item)
	}
	// 签名验证
	err := wxpay.VerifyWXMLResult(tmpData)
	if err != nil {
		addErrorLog("WechatpayRefundOa", "签名验证失败 body "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("签名验证失败"))
		return
	}

	// 退款信息解密
	data, err := wxpay.DecryptWithAES256ECB(tmpData["req_info"])
	if err != nil {
		addErrorLog("WechatpayRefundOa", "退款信息解密失败 body "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("退款信息解密失败"))
		return
	}

	/*
			返回示例
			<xml>
		<return_code>SUCCESS</return_code>
		   <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
		   <mch_id><![CDATA[10000100]]></mch_id>
		   <nonce_str><![CDATA[TeqClE3i0mvn3DrK]]></nonce_str>
		   <req_info><![CDATA[T87GAHG17TGAHG1TGHAHAHA1Y1CIOA9UGJH1GAHV871HAGAGQYQQPOOJMXNBCXBVNMNMAJAA]]></req_info>
		</xml>
		req_info解密后的示例：
		<root>
		<out_refund_no><![CDATA[131811191610442717309]]></out_refund_no>
		<out_trade_no><![CDATA[71106718111915575302817]]></out_trade_no>
		<refund_account><![CDATA[REFUND_SOURCE_RECHARGE_FUNDS]]></refund_account>
		<refund_fee><![CDATA[3960]]></refund_fee>
		<refund_id><![CDATA[50000408942018111907145868882]]></refund_id>
		<refund_recv_accout><![CDATA[支付用户零钱]]></refund_recv_accout>
		<refund_request_source><![CDATA[API]]></refund_request_source>
		<refund_status><![CDATA[SUCCESS]]></refund_status>
		<settlement_refund_fee><![CDATA[3960]]></settlement_refund_fee>
		<settlement_total_fee><![CDATA[3960]]></settlement_total_fee>
		<success_time><![CDATA[2018-11-19 16:24:13]]></success_time>
		<total_fee><![CDATA[3960]]></total_fee>
		<transaction_id><![CDATA[4200000215201811190261405420]]></transaction_id>
		</root>
	*/

	if data["refund_status"] != "SUCCESS" {
		addErrorLog("WechatpayRefundOa", "refund_status不对 "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("refund_status不对"))
		return
	}

	// 签名通过
	// 查询 pay_log 是否有记录
	ctx := r.GetCtx()
	var prModel *entity.PayRefund
	err = toolsDb.GetUnSafaTable(ctx, "pay_refund").Where(
		"refund_no", data["out_refund_no"]).
		Struct(&prModel)
	if err != nil {
		addErrorLog("WechatpayRefundOa", "pay_refund 找不到数据 "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("记录不存在"))
		return
	}
	if prModel == nil {
		addErrorLog("WechatpayRefundOa", "pay_refund 找不到数据 "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("记录不存在"))
		return
	}

	// 如果状态 99 直接给微信返回成功
	if prModel.Status == 99 {
		r.Response.WriteXmlExit(mch.ReplyOK())
		return
	}

	if prModel.Status != 0 {
		addErrorLog("WechatpayRefundOa", "pay_refund status 不为0 "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("状态不正确"))
		return
	}

	tmps := strings.Split(prModel.RefundNo, "R")
	if len(tmps) != 2 {
		addErrorLog("WechatpayRefundOa", "pay_refund refund_no 解析失败 "+r.GetBodyString())
		r.Response.WriteXmlExit(mch.ReplyFail("记录不存在"))
		return
	}

	// 更新 pay_refund
	_, err = toolsDb.GetUnSafaTable(ctx, "pay_refund").Where("id", prModel.Id).Update(g.Map{
		"update_time": tools.MakeTimestamp(),
		"status":      99,
	})
	if err != nil {
		addErrorLog("WechatpayRefundOa", "更新 pay_refund 失败 id:"+gconv.String(prModel.Id)+
			" error:"+err.Error())
		return
	}
	r.Response.WriteXmlExit(mch.ReplyOK())
	return
}
